package com.ld.shieldsb.codegen.service;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.security.SecureRandom;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.ld.shieldsb.codegen.model.export.ExportFile;
import com.ld.shieldsb.codegen.model.export.ExportParams;
import com.ld.shieldsb.codegen.model.export.ExportParamsModelFieldsModel;
import com.ld.shieldsb.codegen.model.export.ExportResult;
import com.ld.shieldsb.common.composition.util.ConvertUtil;
import com.ld.shieldsb.common.core.collections.ListUtils;
import com.ld.shieldsb.common.core.io.FileUtils;
import com.ld.shieldsb.common.core.model.PropertiesModel;
import com.ld.shieldsb.common.core.util.BeetlUtil;
import com.ld.shieldsb.common.core.util.DateUtil;
import com.ld.shieldsb.common.core.util.StringUtils;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Data
@Slf4j
/**
 * 生成代码的服务
 * 
 * @ClassName EntityService
 * @author <a href="mailto:donggongai@126.com" target="_blank">kevin</a>
 * @date 2016年8月24日 下午2:34:37
 *
 */
public class CodeGenService {
    // 常用词默认配置，index0为原始字符1为转换后字符
    private static final String[][] COMMON_WORDS_DEFAULT = { { "username", "userName" }, { "createby", "createBy" },
            { "createname", "createName" }, { "createtime", "createTime" }, { "modifytime", "modifyTime" }, { "modifyby", "modifyBy" },
            { "updateby", "updateBy" }, { "updatename", "updateName" }, { "updatetime", "updateTime" }, { "approvedby", "approvedBy" },
            { "approvedname", "approvedName" }, { "approvedtime", "approvedTime" } };
    // 更新页面不可更新字段
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static final List<String> UN_UPDATED_FIELD = new ArrayList(
            Arrays.asList("id", "createby", "createname", "createtime", "updateby", "updatename", "updatetime", "status"));
    private static final Map<String, String> COMMON_WORDS_MAP = new HashMap<>();

    private static final String EXTENSION_TYPE_JAVA = ".java";
    private static final String EXTENSION_TYPE_JSP = ".jsp";

    // 导出类型
    public static final String EXPORT_TYPE_MODEL = "0";
    public static final String EXPORT_TYPE_DAO = "1";
    public static final String EXPORT_TYPE_SERVICE = "2";
    public static final String EXPORT_TYPE_JSP = "3";
    public static final String EXPORT_TYPE_CONTROLLER = "4";

    private static final String DATETIME_FORMAT = "yyyy年MM月dd日 HH:mm:ss";

    /**
     * 
     * 输出代码（根据参数选择模板）
     * 
     * @Title createCode
     * @author 吕凯
     * @date 2018年12月19日 下午5:13:32
     * @param outTypes
     *            导出类型
     * @param tableList
     *            table数据包
     * @param packagePrefix
     *            包名前缀
     * @param packageSuffix
     *            包名后缀
     * @param classNamePrefix
     *            类名前缀
     * @param jspdir
     *            jsp输出目录
     * @param dic
     *            输出目录
     * @return
     * @throws SQLException
     *             int
     */
    public static ExportResult createCode(List<String> outTypes, ExportParams params) {
        ExportResult result = new ExportResult();
        String packagePrefix = params.getPackagePrefix();
        String packageSuffix = params.getPackageSuffix();
        String classNamePrefix = params.getClassName();
        String dic = params.getOutDir();
        File dicFile = new File(dic);
        if (!dicFile.exists()) { // 目录不存在则创建
            dicFile.mkdirs();
        }
        if (ListUtils.isNotEmpty(outTypes)) {
            List<ExportParamsModelFieldsModel> tableColList = params.getColumns();
            String modelcomments = params.getModelComments();
            String tableName = params.getTableName();

            String pkgName = packagePrefix + ".model";
            if (StringUtils.isNotBlank(packageSuffix)) {
                pkgName += "." + packageSuffix;
            }
            String className = classNamePrefix + "Model";
            String modelName = className;
            params.setTableName(tableName);
            params.setPkgName(pkgName);
            params.setClassName(className);
//            params.setModelPackage(pkgName); //model中处理
            params.setModelName(modelName);
            params.setModelComments(modelcomments);
            // 实体类
            if (outTypes.contains(EXPORT_TYPE_MODEL)) {
                result.setModelFile(exportModel(params, tableColList));
            }
            // dao“需要依赖于model
            if (outTypes.contains(EXPORT_TYPE_DAO)) {
                pkgName = parsePkgName(EXPORT_TYPE_DAO, packagePrefix, packageSuffix);
                className = classNamePrefix + "DAO";
                params.setPkgName(pkgName);
                params.setClassName(className);
                result.setDaoFile(exportDAO(params));
            }

            // service
            if (outTypes.contains(EXPORT_TYPE_SERVICE)) {
                pkgName = parsePkgName(EXPORT_TYPE_SERVICE, packagePrefix, packageSuffix);
                className = classNamePrefix + "Service";
                params.setPkgName(pkgName);
                params.setClassName(className);

                params.setServicePackage(pkgName); // service包名，用于controller中
                params.setServiceName(className); // service类名，用于controller中

                result.setServiceFile(exportService(params));
            }

            // jsp
            if (outTypes.contains(EXPORT_TYPE_JSP)) {
                result.setJspFiles(exportJsp(params, tableColList));
            }

            // controller：需要依赖于model、jsp
            if (outTypes.contains(EXPORT_TYPE_CONTROLLER)) {
                pkgName = parsePkgName(EXPORT_TYPE_CONTROLLER, packagePrefix, packageSuffix);
                className = classNamePrefix + "Controller";
                if (StringUtils.isNotBlank(packageSuffix)) {
                    params.setControllerName(packageSuffix + className);
                }
                params.setPkgName(pkgName);
                params.setClassName(className);
                result.setControllerFile(exportController(params));
            }

        }
        return result;
    }

    /**
     * 处理包名
     * 
     * @Title parsePkgName
     * @author 吕凯
     * @date 2018年12月21日 下午2:58:06
     * @param outType
     * @param packagePrefix
     * @param packageSuffix
     * @return String
     */
    private static String parsePkgName(String outType, String packagePrefix, String packageSuffix) {
        String pkgName = "";
        if (EXPORT_TYPE_DAO.equals(outType)) {
            pkgName = packagePrefix + ".dao";
        }
        if (EXPORT_TYPE_SERVICE.equals(outType)) {
            pkgName = packagePrefix + ".service";
        }
        if (EXPORT_TYPE_CONTROLLER.equals(outType)) {
            pkgName = packagePrefix + ".controller";
        }
        if (StringUtils.isNotBlank(packageSuffix)) {
            pkgName += "." + packageSuffix;
        }
        return pkgName;
    }

    /**
     * 
     * 导出model
     * 
     * @Title exportModel
     * @author 吕凯
     * @date 2018年12月20日 上午9:15:46
     * @param tableComments
     * @param packeage
     * @param tableName
     * @param className
     * @param tableColList
     * @param dic
     * @return String
     */
    private static ExportFile exportModel(ExportParams params, List<ExportParamsModelFieldsModel> tableColList) {
        ExportFile file = new ExportFile();
        String packeage = params.getPkgName();
        String className = params.getClassName();
        String dic = params.getOutDir();
        params.setNowTime(DateUtil.getNowDateTime(DATETIME_FORMAT));
        Map<String, Object> model = new HashMap<>();
        try {
            model = ConvertUtil.obj2OrigMap(params);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            log.error("", e);
        }
        model.put("serialID", new SecureRandom().nextLong() + "L"); // 序列化的编号
        model.put("fieldList", tableColList); // tableColList数据
        String templDir = getTemplDir(params);
        String content = "";
        String modelTempl = params.getModelTempl();
        if (StringUtils.isNotEmpty(modelTempl)) {
            content = BeetlUtil.render(templDir + modelTempl, model); // 模板中获取
        }
        String outdir = parseOutDir(packeage, dic + params.getJavaMainDir());
        file.setContent(content);
        file.setName(className + EXTENSION_TYPE_JAVA);
        if (!params.isPreview()) { // 非预览则直接导出
            file.setFileNotNull(outFile(className, outdir, content, EXTENSION_TYPE_JAVA));
        }
        return file;
    }

    /**
     * 获取模板目录
     * 
     * @Title getTemplDir
     * @author 吕凯
     * @date 2019年7月12日 下午2:41:43
     * @param params
     * @return String
     */
    private static String getTemplDir(ExportParams params) {
        String templDir = params.getTemplDir();
        if (templDir == null) {
            templDir = "";
        }
        templDir = "codegen/" + templDir + "/";
        templDir = templDir.replace("/+", "/");
        return templDir;
    }

    /**
     * 导出DAO文件
     * 
     * @Title exportDAO
     * @author 吕凯
     * @date 2016年8月23日 上午9:22:48
     * @param tableComments
     * @param dic
     * @param createDAO
     *            void
     */
    private static ExportFile exportDAO(ExportParams params) {
        ExportFile file = new ExportFile();

        String packeage = params.getPkgName();
        String className = params.getClassName();
        String dic = params.getOutDir();
        params.setNowTime(DateUtil.getNowDateTime(DATETIME_FORMAT));
        Map<String, Object> model = new HashMap<>();
        try {
            model = ConvertUtil.obj2OrigMap(params);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            log.error("", e);
        }
        String templDir = getTemplDir(params);
        String content = "";
        String modelTempl = params.getDaoTempl();
        if (StringUtils.isNotEmpty(modelTempl)) {
            content = BeetlUtil.render(templDir + modelTempl, model); // 模板中获取
        }
        String outdir = parseOutDir(packeage, dic + params.getJavaMainDir());
        file.setContent(content);
        file.setName(className + EXTENSION_TYPE_JAVA);
        if (!params.isPreview()) { // 非预览则直接导出
            file.setFileNotNull(outFile(className, outdir, content, EXTENSION_TYPE_JAVA));
        }
        return file;
    }

    private static ExportFile exportService(ExportParams params) {
        ExportFile file = new ExportFile();

        String packeage = params.getPkgName();
        String className = params.getClassName();
        String dic = params.getOutDir();
        params.setNowTime(DateUtil.getNowDateTime(DATETIME_FORMAT));
        Map<String, Object> model = new HashMap<>();
        try {
            model = ConvertUtil.obj2OrigMap(params);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            log.error("", e);
        }
        String templDir = getTemplDir(params);
        String content = "";
        String modelTempl = params.getServiceTempl();
        if (StringUtils.isNotEmpty(modelTempl)) {
            content = BeetlUtil.render(templDir + modelTempl, model); // 模板中获取
//            content = BeetlUtil.render(templDir + "service.html", model); // 模板中获取
        }
        String outdir = parseOutDir(packeage, dic + params.getJavaMainDir());
        file.setContent(content);
        file.setName(className + EXTENSION_TYPE_JAVA);
        if (!params.isPreview()) { // 非预览则直接导出
            file.setFileNotNull(outFile(className, outdir, content, EXTENSION_TYPE_JAVA));
        }
        return file;
    }

    private static List<ExportFile> exportJsp(ExportParams params, List<ExportParamsModelFieldsModel> tableColList) {
        List<ExportFile> fileList = new ArrayList<>();
        String dic = params.getOutDir();
        String jspdir = params.getJspDir(); // 模块路径，完整路径需要outDir+jspMainDir+jspDir
        params.setNowTime(DateUtil.getNowDateTime(DATETIME_FORMAT));
        Map<String, Object> model = new HashMap<>();
        try {
            model = ConvertUtil.obj2OrigMap(params);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            log.error("", e);
        }
        model.put("fieldList", tableColList); // tableColList数据
        String templDir = getTemplDir(params);
        String content = "";
        String outdir = parseOutDir(jspdir, dic + params.getJspMainDir());

        String modelTempl = params.getJspTempl(); // 逗号连接多个文件
        if (StringUtils.isNotEmpty(modelTempl)) {
            // content = BeetlUtil.render(templDir + modelTempl, model); // 模板中获取
            String[] modelTemplArrs = modelTempl.split(",");
            for (int i = 0; i < modelTemplArrs.length; i++) {
                String modelTemplPath = modelTemplArrs[i];
                if (modelTemplPath.contains("jsp/")) {
                    modelTemplPath = modelTemplPath.replaceFirst("jsp/", ""); // 去除jsp
                }
                content = BeetlUtil.render(templDir + "jsp/" + modelTemplPath, model); // 模板中获取
                String modelTemplName = StringUtils.substringBeforeLast(modelTemplPath, ".");
                ExportFile file = new ExportFile();
                file.setContent(content);
                file.setName(params.getJspPrefix() + "_" + modelTemplName + ".jsp");
                if (!params.isPreview()) { // 非预览则直接导出
                    file.setFileNotNull(outFile(params.getJspPrefix() + "_" + modelTemplName, outdir, content, EXTENSION_TYPE_JSP));
                }
                fileList.add(file);
            }

        }

//        content = BeetlUtil.render(templDir + "jsp/search.html", model); // 模板中获取
//        ExportFile file = new ExportFile();
//        file.setContent(content);
//        file.setName(params.getJspPrefix() + "_search.jsp");
//        if (!params.isPreview()) { // 非预览则直接导出
//            file.setFileNotNull(outFile(params.getJspPrefix() + "_search", outdir, content, EXTENSION_TYPE_JSP));
//        }
//        fileList.add(file);
//        content = BeetlUtil.render(templDir + "jsp/list.html", model); // 模板中获取
//        file = new ExportFile();
//        file.setContent(content);
//        file.setName(params.getJspPrefix() + "_list.jsp");
//        if (!params.isPreview()) { // 非预览则直接导出
//            file.setFileNotNull(outFile(params.getJspPrefix() + "_list", outdir, content, EXTENSION_TYPE_JSP));
//        }
//        fileList.add(file);
//        file = new ExportFile();
//        content = BeetlUtil.render(templDir + "jsp/show.html", model); // 模板中获取
//
//        file = new ExportFile();
//        file.setContent(content);
//        file.setName(params.getJspPrefix() + "_show.jsp");
//        if (!params.isPreview()) { // 非预览则直接导出
//            file.setFileNotNull(outFile(params.getJspPrefix() + "_show", outdir, content, EXTENSION_TYPE_JSP));
//        }
//        fileList.add(file);
//        content = BeetlUtil.render(templDir + "jsp/update.html", model); // 模板中获取
//
//        file = new ExportFile();
//        file.setContent(content);
//        file.setName(params.getJspPrefix() + "_update.jsp");
//        if (!params.isPreview()) { // 非预览则直接导出
//            file.setFileNotNull(outFile(params.getJspPrefix() + "_update", outdir, content, EXTENSION_TYPE_JSP));
//        }
//        fileList.add(file);
        // 是否带导入功能
        if (params.isHasImport() && !modelTempl.contains("import.html")) {
            content = BeetlUtil.render(templDir + "jsp/import.html", model); // 模板中获取

            ExportFile file = new ExportFile();
            file.setContent(content);
            file.setName(params.getJspPrefix() + "_import.jsp");
            if (!params.isPreview()) { // 非预览则直接导出
                file.setFileNotNull(outFile(params.getJspPrefix() + "_import", outdir, content, EXTENSION_TYPE_JSP));
            }
            fileList.add(file);
        }

        return fileList;
    }

    /**
     * 导出controller
     * 
     * @Title exportController
     * @author 吕凯
     * @date 2018年12月20日 上午9:15:30
     * @param tableComments
     * @param packeage
     * @param className
     * @param modelName
     * @param dic
     * @return String
     */
    private static ExportFile exportController(ExportParams params) {
        ExportFile file = new ExportFile();
        String packeage = params.getPkgName();
        String className = params.getClassName();
        String dic = params.getOutDir();
        params.setNowTime(DateUtil.getNowDateTime(DATETIME_FORMAT));
        Map<String, Object> model = new HashMap<>();
        try {
            model = ConvertUtil.obj2OrigMap(params);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            log.error("", e);
        }
        String templDir = getTemplDir(params);
        String content = "";
        content = BeetlUtil.render(templDir + "controller.html", model); // 模板中获取

        String outdir = parseOutDir(packeage, dic + params.getJavaMainDir());
        file.setContent(content);
        file.setName(className + EXTENSION_TYPE_JAVA);
        if (!params.isPreview()) { // 非预览则直接导出
            file.setFileNotNull(outFile(className, outdir, content, EXTENSION_TYPE_JAVA));
        }
        return file;
    }

    /**
     * 根据根目录和package的名字处理输出目录
     * 
     * @Title parseOutDir
     * @author 吕凯
     * @date 2018年12月20日 上午9:40:10
     * @param packeage
     * @param dic
     * @return String
     */
    private static String parseOutDir(String packeage, String dic) {
        String outdir = dic;
        if (packeage != null) {
            outdir += "/" + packeage.replaceAll("\\.", "/");
        }
        outdir = outdir.replaceAll("\\/+", "/");
        return outdir;
    }

    /**
     * 导出文件
     * 
     * @Title outFile
     * @author 吕凯
     * @date 2016年8月31日 下午3:59:56
     * @param tablename
     * @param dic
     * @param daoContent
     * @param filtType
     *            void
     */
    private static ExportFile outFile(String tablename, String dic, String fileContent, String fielType) {
        ExportFile exprotFile = new ExportFile();

        exprotFile.setContent(fileContent);
        File file = new File(dic, tablename + fielType);
        FileUtils.writeToFile(file.getAbsolutePath(), fileContent, false);
        exprotFile.setName(file.getName());
        exprotFile.setExtension(FileUtils.getFileExtension(file.getAbsolutePath()));
        exprotFile.setPath(file.getAbsolutePath());
        log.warn("导出文件：" + file.getAbsolutePath());
        return exprotFile;
    }

    /**
     * 解析为符合编码规范的类名称
     * 
     * @Title parseClassName
     * @author 吕凯
     * @date 2016年8月25日 下午2:23:52
     * @param str
     * @return String
     */
    public static String parseClassName(String str) {
        return StringUtils.cap(parseFieldName(str));
    }

    /**
     * 解析为符合编码规范的字段名称
     * 
     * @Title parseFieldName
     * @author 吕凯
     * @date 2016年8月25日 下午2:23:19
     * @param str
     * @return String
     */

    public static String parseFieldName(String str) {
        str = str.toLowerCase();// 转换为小写
        String key = str;
        COMMON_WORDS_MAP.clear();
        // 默认配置，可被后面的设置覆盖
        Arrays.asList(COMMON_WORDS_DEFAULT).stream().forEach(commonWordSetArrs -> {
            COMMON_WORDS_MAP.put(commonWordSetArrs[0], commonWordSetArrs[1]);
        });
//        Map<String, String> commonWordsMap = null;
//        try {
//            commonWordsMap = CacheUtil.get(ConfigProperties.CACHE_COMMON_WORDS);
//        } catch (Exception e) {
//            log.error("获取常用词设置缓存失败！", e);
//        }
//        if (commonWordsMap != null && commonWordsMap.size() > 0) {
//            COMMON_WORDS_MAP.putAll(commonWordsMap);
//        }
        if (COMMON_WORDS_MAP != null && COMMON_WORDS_MAP.size() > 0 && COMMON_WORDS_MAP.containsKey(key)) {
            str = COMMON_WORDS_MAP.get(key);
            return str;
        } else {
            str = splitWordSet(str);
            return StringUtils.toCamelCase(str);
        }
    }

    /**
     * 根据设置的单词进行划分
     * 
     * @Title splitWordSet
     * @author 吕凯
     * @date 2016年8月25日 上午11:37:29
     * @param str
     * @return String
     */
    private static String splitWordSet(String str) {
        String wordSet = PropertiesModel.CONFIG.getString("wordset");
        if (!StringUtils.isBlank(wordSet)) {
            wordSet = wordSet.replace(",", "|");
            Pattern humpPattern = Pattern.compile(wordSet);
            Matcher matcher = humpPattern.matcher(str);
            StringBuffer sb = new StringBuffer();
            while (matcher.find()) {
                matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
            }
            matcher.appendTail(sb);
            str = sb.toString();
            if (str.startsWith("_")) {
                str = StringUtils.substringAfter(str, "_");
            }
        }
        return str;
    }

    /**
     * 执行方法
     */
    public static void main(String[] args) throws SQLException {
        String source = "mobilephone";
        System.out.println(parseFieldName(source));

    }
}
